home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / screen32.lha / screen-3.2b / mark.c < prev    next >
C/C++ Source or Header  |  1992-02-02  |  25KB  |  1,145 lines

  1. /* Copyright (c) 1991
  2.  *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
  3.  *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
  4.  * Copyright (c) 1987 Oliver Laumann
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 1, or (at your option)
  9.  * any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program (see the file COPYING); if not, write to the
  18.  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  * Noteworthy contributors to screen's design and implementation:
  21.  *    Wayne Davison (davison@borland.com)
  22.  *    Patrick Wolfe (pat@kai.com, kailand!pat)
  23.  *    Bart Schaefer (schaefer@cse.ogi.edu)
  24.  *    Nathan Glasser (nathan@brokaw.lcs.mit.edu)
  25.  *    Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
  26.  *    Howard Chu (hyc@hanauma.jpl.nasa.gov)
  27.  *    Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
  28.  *    Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
  29.  *    Marc Boucher (marc@CAM.ORG)
  30.  *
  31.  ****************************************************************
  32.  */
  33.  
  34. #ifndef lint
  35.   static char rcs_id[] = "$Id: mark.c,v 1.2 92/02/03 02:27:48 jnweiger Exp $ FAU";
  36. #endif
  37.  
  38. #include <sys/types.h>
  39.  
  40. #ifdef BSD
  41. # include <sys/signal.h>
  42. #endif /* BSDI */
  43.  
  44. #include "config.h"
  45. #include "screen.h"
  46. #include "ansi.h"    /* here we find A_SO, ASCII, EXPENSIVE */
  47. #include "extern.h"
  48.  
  49. static int is_letter __P((int));
  50. static void nextword __P((int *, int *, int, int));
  51. static int linestart __P((int));
  52. static int lineend __P((int));
  53. static int rem __P((int, int , int , int , int , char *, int));
  54. static int eq __P((int, int ));
  55. static void revto __P((int, int));
  56. static void revto_line __P((int, int, int));
  57. static void MarkRedisplayLine __P((int, int, int, int));
  58. static int MarkRewrite __P((int, int, int, int));
  59. static void process_mark_input __P((char **, int *));
  60. static void AbortMarkRoutine __P((void));
  61. static int MarkScrollDownDisplay __P((int));
  62. static int MarkScrollUpDisplay __P((int));
  63.  
  64. int join_with_cr =  0;
  65. extern struct win *fore, *wtab[];
  66. extern int screenwidth, screenheight;
  67. extern int screentop, screenbot;
  68. extern char GlobalAttr, GlobalCharset;
  69. extern int in_ovl;
  70. extern int HS;
  71. extern int LP;
  72. extern char *null, *blank;
  73.  
  74. #ifdef NETHACK
  75. extern nethackflag;
  76. #endif
  77.  
  78. char *copybuffer = NULL;
  79. int copylen = 0;
  80. char mark_key_tab[256]; /* this array must be initialised first! */
  81.  
  82. static int in_mark;    /* mark routine active */
  83. static int left_mar, right_mar, nonl;
  84. static int x1, y1, second; /* y1 is in terms of WIN coordinates, not DISPLAY */
  85. static int cx, cy;    /* Cursor Position in WIN coords*/
  86. static rep_cnt;        /* no. of repeats are rep_cnt+1. jw. */
  87. static int append_mode;    /* shall we overwrite or append to copybuffer */
  88. static write_buffer;    /* shall we do a KEY_WRITE_EXCHANGE right away? */
  89. static hist_offset;
  90.  
  91. static int is_letter(c)
  92. char c;
  93. {
  94.   if ((c >= 'a' && c <= 'z') ||
  95.       (c >= 'A' && c <= 'Z') ||
  96.       (c >= '0' && c <= '9') ||
  97.       c == '_' || c == '.' ||
  98.       c == '@' || c == ':' ||
  99.       c == '%' || c == '!' ||
  100.       c == '-' || c == '+')
  101.     /* thus we can catch email-addresses as a word :-) */
  102.     return 1;
  103.   else if (c != ' ')
  104.     return 2;
  105.   return 0;
  106. }
  107.  
  108. /*
  109.  * iWIN gives us a reference to line y of the *whole* image 
  110.  * where line 0 is the oldest line in our history.
  111.  * y must be in WIN coordinate system, not in display.
  112.  */
  113. #define iWIN(y) ((y < fore->histheight) ? fore->ihist[(fore->histidx + y)\
  114.         % fore->histheight] : fore->image[y - fore->histheight])
  115. #define aWIN(y) ((y < fore->histheight) ? fore->ahist[(fore->histidx + y)\
  116.         % fore->histheight] : fore->attr[y - fore->histheight])
  117. #define fWIN(y) ((y < fore->histheight) ? fore->fhist[(fore->histidx + y)\
  118.         % fore->histheight] : fore->font[y - fore->histheight])
  119. /*
  120.  * hist_offset tells us, how many lines there are on top of the
  121.  * visible screen.
  122.  */
  123.  
  124. #define W2D(y) ((y)-hist_offset)
  125. #define D2W(y) ((y)+hist_offset)
  126.  
  127. static int
  128. linestart(y)
  129. int y;
  130. {
  131.   register int x;
  132.   register char *i;
  133.  
  134.   for (x = left_mar, i = iWIN(y) + x; x < screenwidth-1; x++)
  135.     if (*i++ != ' ')
  136.       break;
  137.   if (x == screenwidth-1)
  138.     x = left_mar;
  139.   return(x);
  140. }
  141.  
  142. static int
  143. lineend(y)
  144. int y;
  145. {
  146.   register int x;
  147.   register char *i;
  148.  
  149.   for (x = right_mar, i = iWIN(y) + x; x >= 0; x--)
  150.     if (*i-- != ' ')
  151.       break;
  152.   if (x < 0)
  153.     x = left_mar;
  154.   return(x);
  155. }
  156.  
  157.  
  158. /*
  159.  *  nextword calculates the cursor position of the num'th word.
  160.  *  If the cursor is on a word, it counts as the first.
  161.  *  NW_BACK:        search backward
  162.  *  NW_ENDOFWORD:    find the end of the word
  163.  *  NW_MUSTMOVE:    move even if the position is correct.
  164.  */
  165.  
  166. #define NW_BACK        1
  167. #define NW_ENDOFWORD    2
  168. #define NW_MUSTMOVE    4
  169.  
  170. static void
  171. nextword(xp, yp, flags, num)
  172. int *xp, *yp, flags, num;
  173. {
  174.   int xx = screenwidth, yy = fore->histheight + screenheight;
  175.   register int sx, oq, q, x, y;
  176.  
  177.   x = *xp;
  178.   y = *yp;
  179.   sx = (flags & NW_BACK) ? -1 : 1;
  180.   if ((flags & NW_ENDOFWORD) && (flags & NW_MUSTMOVE))
  181.     x += sx;
  182.   for (oq = -1; ; x += sx, oq = q)
  183.     {
  184.       if (x >= xx || x < 0)
  185.     q = 0;
  186.       else
  187.         q = is_letter(iWIN(y)[x]);
  188.       if (oq >= 0 && oq != q)
  189.     {
  190.       if (oq == 0 || !(flags & NW_ENDOFWORD))
  191.         *xp = x;
  192.       else
  193.         *xp = x-sx;
  194.       *yp = y;
  195.       if ((!(flags & NW_ENDOFWORD) && q) ||
  196.           ((flags & NW_ENDOFWORD) && oq))
  197.         {
  198.           if (--num <= 0)
  199.             return;
  200.         }
  201.     }
  202.       if (x == xx)
  203.     {
  204.       x = -1;
  205.       if (++y >= yy)
  206.         return;
  207.     }
  208.       else if (x < 0)
  209.     {
  210.       x = xx;
  211.       if (--y < 0)
  212.         return;
  213.     }
  214.     }
  215. }
  216.  
  217.  
  218. /*
  219.  * y1, y2 are WIN coordinates
  220.  *
  221.  * redisplay:    0  -  just copy
  222.  *         1  -  redisplay + copy
  223.  *        2  -  count + copy, don't redisplay
  224.  */
  225.  
  226. static int rem(x1, y1, x2, y2, redisplay, pt, yend)
  227. int x1, y1, x2, y2, redisplay, yend;
  228. char *pt;
  229. {
  230.   int i, j, from, to, ry;
  231.   int l = 0;
  232.   char *im;
  233.  
  234.   second = 0;
  235.   if (y2 < y1 || ((y2 == y1) && (x2 < x1)))
  236.     {
  237.       i = y2;
  238.       y2 = y1;
  239.       y1 = i;
  240.       i = x2;
  241.       x2 = x1;
  242.       x1 = i;
  243.     }
  244.   ry = y1 - hist_offset;
  245.   
  246.   i = y1;
  247.   if (redisplay != 2 && pt == 0 && ry <0)
  248.     {
  249.       i -= ry;
  250.       ry = 0;
  251.     }
  252.   for (; i <= y2; i++, ry++)
  253.     {
  254.       if (redisplay != 2 && pt == 0 && ry > yend)
  255.     break;
  256.       from = (i == y1) ? x1 : 0;
  257.       if (from < left_mar)
  258.     from = left_mar;
  259.       for (to = screenwidth-1, im = iWIN(i)+to; to>=0; to--)
  260.         if (*im-- != ' ')
  261.       break;
  262.       if (i == y2 && x2 < to)
  263.     to = x2;
  264.       if (to > right_mar)
  265.     to = right_mar;
  266.       if (redisplay == 1 && from <= to && ry >=0 && ry <= yend)
  267.     MarkRedisplayLine(ry, from, to, 0);
  268.       if (redisplay != 2 && pt == 0)    /* don't count/copy */
  269.     continue;
  270.       for (j = from, im = iWIN(i)+from; j <= to; j++)
  271.     {
  272.       if (pt)
  273.         *pt++ = *im++;
  274.       l++;
  275.     }
  276.       if (i != y2)
  277.     {
  278.       /* 
  279.        * this code defines, what glues lines together
  280.        */
  281.       switch (nonl)
  282.         {
  283.         case 0:        /* lines separated by newlines */
  284.           if (join_with_cr)
  285.         {
  286.           if (pt)
  287.             *pt++ = '\r';
  288.           l++;
  289.         }
  290.           if (pt)
  291.         *pt++ = '\n';
  292.           l++;
  293.           break;
  294.         case 1:        /* nothing to separate lines */
  295.           break;
  296.         case 2:        /* lines separated by blanks */
  297.           if (pt)
  298.         *pt++ = ' ';
  299.           l++;
  300.           break;
  301.         }
  302.     }
  303.     }
  304.   return(l);
  305. }
  306.  
  307. static int eq(a, b)
  308. int a, b;
  309. {
  310.   if (a == b)
  311.     return 1;
  312.   if (a == 0 || b == 0)
  313.     return 1;
  314.   if (a <= '9' && a >= '0' && b <= '9' && b >= '0')
  315.     return 1;
  316.   return 0;
  317. }
  318.  
  319. static int crazychar = 0;
  320. static int crazy_y = -1;
  321. static int crazy_x = -1;
  322.  
  323. int MarkRoutine(flag)    /* return value 1 when copybuffer changed; */
  324. int flag;
  325. {
  326.   int x, y, i;
  327.  
  328.   hist_offset = fore->histheight;
  329.  
  330.   if (!fore->active)
  331.     {
  332.       Msg(0, "Fore window is not active !!!");
  333.       return 0;
  334.     }
  335.  
  336.   second = 0;
  337.   rep_cnt = 0;
  338.   append_mode = 0;
  339.   write_buffer = 0;
  340.   nonl = left_mar = 0;
  341.   right_mar = screenwidth-1;
  342.   x = fore->x;
  343.   y = D2W(fore->y);
  344.   if (x >= screenwidth)
  345.     x = screenwidth-1;
  346.  
  347.   if (flag == CRAZY && crazychar != 0 && crazy_x != -1 && crazy_y != -1)
  348.     {
  349.       Msg(0, "CRAZY mode not impl.\n");
  350.     }
  351.   crazychar = 0;
  352.   crazy_y = -1;
  353.   crazy_x = -1;
  354.   if (flag == TRICKY)
  355.     {
  356.       int f, q = 0, xx, yy;
  357.       char *linep;
  358.  
  359.       debug2("cursor is at x=%d, y=%d\n", fore->x, D2W(fore->y));
  360.       for (xx = fore->x - 1, linep = iWIN(y) + xx; xx >= 0; xx--)
  361.     if ((q = *linep--) != ' ' )
  362.       break;
  363.       debug3("%c at (%d,%d)\n", q, xx, y);
  364.       for (yy = D2W(fore->y) - 1; yy >= 0; yy--)
  365.     if (xx < 0 || eq(iWIN(yy)[xx], q))
  366.       {        /* line is matching... */
  367.         f = 0;
  368.         for (i = fore->x; i < screenwidth-1; i++)
  369.           {
  370.         if (iWIN(yy)[i] != ' ')
  371.           {
  372.             f = 1;
  373.             break;
  374.           }
  375.           }
  376.         if (f)
  377.           break;
  378.       }
  379.       if (yy < 0)
  380.     return 0;
  381.       xx = 0;
  382.       for (i = screenwidth-1, linep = iWIN(yy)+i; i>0; i--)
  383.     if (*linep-- != ' ')
  384.       break;
  385.       if (i < x)
  386.     i = x;
  387.       if (copybuffer != NULL)
  388.     Free(copybuffer);
  389.       if ((copybuffer = malloc((unsigned) (i - x + 2))) == NULL)
  390.     {
  391.       Msg(0, "Not enough memoooh!... Sorry.");
  392.       return 0;
  393.     }
  394.       rem(x, yy, i, yy, 0, copybuffer, 0);
  395.       copylen = i - x + 1;
  396.       return 1;
  397.     }
  398.   InitOverlayPage(process_mark_input, MarkRedisplayLine, MarkRewrite, 1);
  399.   GotoPos(x, W2D(y));
  400. #ifdef NETHACK
  401.   if (nethackflag)
  402.     Msg(0, "Welcome to hacker's treasure zoo - Column %d Line %d(+%d) (%d,%d)",
  403.     x+1, W2D(y+1), fore->histheight, fore->width, fore->height);
  404.   else
  405. #endif
  406.   Msg(0, "Copy mode - Column %d Line %d(+%d) (%d,%d)",
  407.       x+1, W2D(y+1), fore->histheight, fore->width, fore->height);
  408.   fflush(stdout);
  409.   cx = x1 = x;
  410.   cy = y1 = y;
  411.   in_mark = 1;
  412.   return 0;
  413. }
  414.  
  415. static void process_mark_input(inbufp,inlenp)
  416. char **inbufp;
  417. int *inlenp;
  418. {
  419.   char *inbuf, *pt;
  420.   int inlen;
  421.   int x2, y2, i, j, yend;
  422.   int newcopylen = 0, od;
  423. /*
  424.   char *extrap = 0, extrabuf[100];
  425. */
  426.       
  427.   if (inbufp == 0)
  428.     {
  429.       AbortMarkRoutine();
  430.       return;
  431.     }
  432.  
  433.   inbuf= *inbufp;
  434.   inlen= *inlenp;
  435.   pt = inbuf;
  436.   while (in_mark && (inlen /* || extrap */))
  437.     {
  438.       if (!HS)
  439.     RemoveStatus();
  440. /*
  441.       if (extrap)
  442.     {
  443.       od = *extrap++;
  444.       if (*extrap == 0)
  445.         extrap = 0;
  446.     }
  447.       else
  448. */
  449.     {
  450.           od = mark_key_tab[*pt++];
  451.           inlen--;
  452.     }
  453.       if (od >= '0' && od <= '9')
  454.         {
  455.       if (rep_cnt < 1001 && (od != '0' || rep_cnt != 0))
  456.         {
  457.           rep_cnt = 10 * rep_cnt + od - '0';
  458.           continue;
  459.            /*
  460.            * Now what is that 1001 here? Well, we have a screen with
  461.            * 25 * 80 = 2000 characters. Movement is at most across the full
  462.            * screen. This we do with word by word movement, as character by
  463.            * character movement never steps over line boundaries. The most words
  464.            * we can place on the screen are 1000 single letter words. Thus 1001
  465.            * is sufficient. Users with bigger screens never write in single letter
  466.            * words, as they should be more advanced. jw.
  467.            * Oh, wrong. We still give even the experienced user a factor of ten.
  468.            */
  469.         }
  470.     }
  471.       switch (od)
  472.     {
  473.     case '\014':    /* CTRL-L Redisplay */
  474.       Redisplay(0);
  475.       GotoPos(cx, W2D(cy));
  476.       break;
  477.     case '\010':    /* CTRL-H Backspace */
  478.     case 'h':
  479.       if (rep_cnt == 0)
  480.         rep_cnt = 1;
  481.       revto(cx - rep_cnt, cy);
  482.       break;
  483.     case '\016':    /* CTRL-N */
  484.     case 'j':
  485.       if (rep_cnt == 0)
  486.         rep_cnt = 1;
  487.       revto(cx, cy + rep_cnt);
  488.       break;
  489.     case '+':
  490.       if (rep_cnt == 0)
  491.         rep_cnt = 1;
  492.       j = cy + rep_cnt;
  493.       if (j > fore->histheight + screenheight - 1)
  494.         j = fore->histheight + screenheight - 1;
  495.       revto(linestart(j), j);
  496.       break;
  497.     case '-':
  498.       if (rep_cnt == 0)
  499.         rep_cnt = 1;
  500.       j = cy - rep_cnt;
  501.       if (j < 0)
  502.         j = 0;
  503.       revto(linestart(j), j);
  504.       break;
  505.     case '^':
  506.       revto(linestart(cy), cy);
  507.       break;
  508.     case '\n':
  509.       revto(left_mar, cy + 1);
  510.       break;
  511.     case 'k':
  512.     case '\020':    /* CTRL-P */
  513.       if (rep_cnt == 0)
  514.         rep_cnt = 1;
  515.       revto(cx, cy - rep_cnt);
  516.       break;
  517.     case 'l':
  518.       if (rep_cnt == 0)
  519.         rep_cnt = 1;
  520.       revto(cx + rep_cnt, cy);
  521.       break;
  522.     case '\001':    /* CTRL-A from tcsh/emacs */
  523.     case '0':
  524.       revto(left_mar, cy);
  525.       break;
  526.     case '\004':    /* CTRL-D down half screen */
  527.       if (rep_cnt == 0)
  528.         rep_cnt = (screenheight+1) >> 1;
  529.       revto_line(cx, cy + rep_cnt, W2D(cy));
  530.       break;
  531.     case '$':
  532.       revto(lineend(cy), cy);
  533.       break;
  534.     case '\025':    /* CTRL-U up half screen */
  535.       if (rep_cnt == 0)
  536.         rep_cnt = (screenheight+1) >> 1;
  537.       revto_line(cx, cy - rep_cnt, W2D(cy));
  538.       break;
  539.     case '?':
  540.       if (left_mar == 0 && right_mar == screenwidth - 1)
  541.         Msg(0, "Column %d Line %d(+%d)", cx+1, W2D(cy)+1,
  542.         hist_offset);
  543.       else
  544.         Msg(0, "Column %d(%d..%d) Line %d(+%d)", cx+1,
  545.         left_mar+1, right_mar+1, W2D(cy)+1, hist_offset);
  546.       break;
  547.     case '\002':    /* CTRL-B  back one page */
  548.       if (rep_cnt == 0)
  549.         rep_cnt = 1;
  550.       rep_cnt *= (screenheight-1);
  551.       revto(cx, cy - rep_cnt);
  552.       break;
  553.     case '\006':    /* CTRL-F  forward one page */
  554.       if (rep_cnt == 0)
  555.         rep_cnt = 1;
  556.       rep_cnt *= (screenheight-1);
  557.       revto(cx, cy + rep_cnt);
  558.       break;
  559.     case '\005':    /* CTRL-E  scroll up */
  560.       if (rep_cnt == 0)
  561.         rep_cnt = 1;
  562.       rep_cnt = MarkScrollUpDisplay(rep_cnt);
  563.       if (cy < D2W(0))
  564.             revto(cx, D2W(0));
  565.       else
  566.             GotoPos(cx, W2D(cy));
  567.       break;
  568.     case '\031': /* CTRL-Y  scroll down */
  569.       if (rep_cnt == 0)
  570.         rep_cnt = 1;
  571.       rep_cnt = MarkScrollDownDisplay(rep_cnt);
  572.       if (cy > D2W(screenheight-1))
  573.             revto(cx, D2W(screenheight-1));
  574.       else
  575.             GotoPos(cx, W2D(cy));
  576.       break;
  577.     case '@':
  578.       /* it may be usefull to have a key that does nothing */
  579.       break;
  580.     case '%':
  581.       rep_cnt--;
  582.       /* rep_cnt is a percentage for the history buffer */
  583.       if (rep_cnt < 0)
  584.         rep_cnt = 0;
  585.       if (rep_cnt > 100)
  586.         rep_cnt = 100;
  587.       revto_line(left_mar, (rep_cnt * (fore->histheight + screenheight)) / 100, (screenheight-1)/2);
  588.       break;
  589.     case 'g':
  590.       rep_cnt = 1;
  591.       /* FALLTHROUGH */
  592.     case 'G':
  593.       /* rep_cnt is here the WIN line number */
  594.       if (rep_cnt == 0)
  595.         rep_cnt = fore->histheight + screenheight;
  596.       revto_line(left_mar, --rep_cnt, (screenheight-1)/2);
  597.       break;
  598.     case 'H':
  599.       revto(left_mar, D2W(0));
  600.       break;
  601.     case 'M':
  602.       revto(left_mar, D2W((screenheight-1) / 2));
  603.       break;
  604.     case 'L':
  605.       revto(left_mar, D2W(screenheight-1));
  606.       break;
  607.     case '|':
  608.       revto(--rep_cnt, cy);
  609.       break;
  610.     case 'w':
  611.       i = cx;
  612.       j = cy;
  613.       if (rep_cnt == 0)
  614.         rep_cnt = 1;
  615.       nextword(&i, &j, NW_MUSTMOVE, rep_cnt);
  616.       revto(i, j);
  617.       break;
  618.     case 'e':
  619.       i = cx;
  620.       j = cy;
  621.       if (rep_cnt == 0)
  622.         rep_cnt = 1;
  623.       nextword(&i, &j, NW_ENDOFWORD|NW_MUSTMOVE, rep_cnt);
  624.       revto(i, j);
  625.       break;
  626.     case 'b':
  627.       i = cx;
  628.       j = cy;
  629.       if (rep_cnt == 0)
  630.         rep_cnt = 1;
  631.       nextword(&i, &j, NW_BACK|NW_ENDOFWORD|NW_MUSTMOVE, rep_cnt);
  632.       revto(i, j);
  633.       break;
  634.     case 'a':
  635.       append_mode = 1 - append_mode;
  636.       debug1("append mode %d--\n", append_mode);
  637.       Msg(0, (append_mode) ? ":set append" : ":set noappend");
  638.       break;
  639.     case 'v':
  640.     case 'V':
  641.       /* this sets start column to column 9 for VI :set nu users */
  642.       if (left_mar == 8)
  643.         rep_cnt = 1;
  644.       else
  645.         rep_cnt = 9;
  646.       /* FALLTHROUGH */
  647.     case 'c':
  648.     case 'C':
  649.       /* set start column (c) and end column (C) */
  650.       if (second)
  651.         {
  652.           rem(x1, y1, cx, cy, 1, (char *)0, screenheight-1); /* Hack */
  653.           second = 1;    /* rem turns off second */
  654.         }
  655.       rep_cnt--;
  656.       if (rep_cnt < 0)
  657.         rep_cnt = cx;
  658.       if (od != 'C')
  659.         {
  660.           left_mar = rep_cnt;
  661.           if (left_mar > right_mar)
  662.         left_mar = right_mar;
  663.         }
  664.       else
  665.         {
  666.           right_mar = rep_cnt;
  667.           if (left_mar > right_mar)
  668.         right_mar = left_mar;
  669.         }
  670.       if (second)
  671.         {
  672.           int x = cx, y = cy;
  673.           cx = x1; cy = y1;
  674.           revto(x, y);
  675.         }
  676.       if (od == 'v' || od == 'V')
  677.         Msg(0, (left_mar != 8) ? ":set nonu" : ":set nu");
  678.       break;
  679.     case 'J':
  680.       /* how do you join lines in VI ? */
  681.       nonl = (nonl + 1) % 3;
  682.       switch (nonl)
  683.         {
  684.         case 0:
  685.           if (join_with_cr)
  686.         Msg(0, "Multiple lines (CR/LF)");
  687.           else
  688.         Msg(0, "Multiple lines (LF)");
  689.           break;
  690.         case 1:
  691.           Msg(0, "Lines joined");
  692.           break;
  693.         case 2:
  694.           Msg(0, "Lines joined with blanks");
  695.           break;
  696.         }
  697.       break;
  698.     case 'y':
  699.     case 'Y':
  700.       if (!second)
  701.         {
  702.           revto(linestart(cy), cy);
  703.           second++;
  704.           x1 = cx;
  705.           y1 = cy;
  706.         }
  707.       if (--rep_cnt > 0)
  708.         revto(cx, cy + rep_cnt);
  709.       revto(lineend(cy), cy);
  710.       if (od == 'y')
  711.         break;
  712.       /* FALLTHROUGH */
  713.     case 'W':
  714.       if (od == 'W')
  715.         {
  716.           if (rep_cnt == 0)
  717.         rep_cnt = 1;
  718.           if (!second)
  719.         {
  720.           i = cx;
  721.           j = cy;
  722.           nextword(&i, &j, NW_BACK|NW_ENDOFWORD, 1);
  723.           revto(i, j);
  724.           second++;
  725.           x1 = cx;
  726.           y1 = cy;
  727.         }
  728.           i = cx;
  729.           j = cy;
  730.           nextword(&i, &j, NW_ENDOFWORD, rep_cnt);
  731.           revto(i, j);
  732.         }
  733.       /* FALLTHROUGH */
  734.     case 'A':
  735.       if (od == 'A')
  736.         append_mode = 1;
  737.       /* FALLTHROUGH */
  738.     case '>':
  739.       if (od == '>')
  740.         write_buffer = 1;
  741.       /* FALLTHROUGH */
  742.     case ' ':
  743.     case '\r':
  744.       if (!second)
  745.         {
  746.           second++;
  747.           x1 = cx;
  748.           y1 = cy;
  749.           revto(x1, y1);
  750. #ifdef NETHACK
  751.           if (nethackflag)
  752.         Msg(0, "You drop a magic marker - Column %d Line %d",
  753.                 cx+1, W2D(cy)+1, hist_offset);
  754.           else
  755. #endif
  756.           Msg(0, "First mark set - Column %d Line %d", cx+1, cy+1);
  757.           break;
  758.         }
  759.       else
  760.         {
  761.           x2 = cx;
  762.           y2 = cy;
  763.           newcopylen = rem(x1, y1, x2, y2, 2, (char *)0, 0); /* count */
  764.           if (copybuffer != NULL && !append_mode)
  765.         {
  766.           copylen = 0;
  767.           Free(copybuffer);
  768.         }
  769.           if (newcopylen > 0)
  770.         {
  771.           /* the +3 below is for : cr + lf + \0 */
  772.           if (copybuffer != NULL)
  773.             copybuffer = realloc(copybuffer,
  774.             (unsigned) (copylen + newcopylen + 3));
  775.           else
  776.             {
  777.             copylen = 0;
  778.             copybuffer = malloc((unsigned) (newcopylen + 3));
  779.             }
  780.           if (copybuffer == NULL)
  781.             {
  782.               AbortMarkRoutine();
  783.               Msg(0, "Not enough memoooh!... Sorry.");
  784.               copylen = 0;
  785.               copybuffer = NULL;
  786.               break;
  787.             }
  788.           if (append_mode)
  789.             {
  790.               switch (nonl)
  791.             /* 
  792.              * this code defines, what glues lines together
  793.              */
  794.             {
  795.             case 0:
  796.               if (join_with_cr)
  797.                 {
  798.                   copybuffer[copylen] = '\r';
  799.                   copylen++;
  800.                 }
  801.               copybuffer[copylen] = '\n';
  802.               copylen++;
  803.               break;
  804.             case 1:
  805.               break;
  806.             case 2:
  807.               copybuffer[copylen] = ' ';
  808.               copylen++;
  809.               break;
  810.             }
  811.             }
  812.           yend = screenheight - 1;
  813.           if (fore->histheight - hist_offset < screenheight)
  814.             {
  815.               second = 0;
  816.               yend -= MarkScrollUpDisplay(fore->histheight - hist_offset);
  817.             }
  818.           copylen += rem(x1, y1, x2, y2, hist_offset == fore->histheight, copybuffer + copylen, yend);
  819.         }
  820.           if (hist_offset != fore->histheight)
  821.         {
  822.           in_ovl = 0;    /* So we can use Activate() */
  823.           Activate(0);
  824.         }
  825.           ExitOverlayPage();
  826.           if (append_mode)
  827.         Msg(0, "Appended %d characters to buffer",
  828.             newcopylen);
  829.           else
  830.         Msg(0, "Copied %d characters into buffer", copylen);
  831.           if (write_buffer)
  832.         WriteFile(DUMP_EXCHANGE);
  833.           in_mark = 0;
  834.           break;
  835.         }
  836.     default:
  837.       AbortMarkRoutine();
  838. #ifdef NETHACK
  839.       if (nethackflag)
  840.         Msg(0, "You escaped the dungeon.");
  841.       else
  842. #endif
  843.       Msg(0, "Copy mode aborted");
  844.       break;
  845.     }
  846.       rep_cnt = 0;
  847.     }
  848.   fflush(stdout);
  849.   *inbufp = pt;
  850.   *inlenp = inlen;
  851. }
  852.  
  853. static void revto(tx, ty)
  854. int tx, ty;
  855. {
  856.   revto_line(tx, ty, -1);
  857. }
  858.  
  859. /* tx, ty: WINDOW,  line: DISPLAY */
  860. static void revto_line(tx, ty, line)
  861. int tx, ty, line;
  862. {
  863.   int fx, fy;
  864.   int x, y, t, revst, reven, qq, ff, tt, st, en, ce = 0;
  865.   int ystart = 0, yend = screenheight-1;
  866.   int i, ry;
  867.  
  868.   if (tx < 0)
  869.     tx = 0;
  870.   else if (tx > screenwidth - 1)
  871.     tx = screenwidth -1;
  872.   if (ty < 0)
  873.     ty = 0;
  874.   else if (ty > fore->histheight + screenheight - 1)
  875.     ty = fore->histheight + screenheight - 1;
  876.   
  877.   fx = cx; fy = cy;
  878.   cx = tx; cy = ty;
  879. /*debug2("revto(%d, %d, ", x1, y1);
  880.   debug2("%d, %d, ", fx, fy);
  881.   debug2("%d, %d)\n", tx, ty);*/
  882.  
  883.   /*
  884.    * if we go to a position that is currently offscreen 
  885.    * then scroll the screen
  886.    */
  887.   i = 0;
  888.   if (line >= 0 && line < screenheight)
  889.     i = W2D(ty) - line;
  890.   else if (ty < hist_offset)
  891.     i = ty - hist_offset;
  892.   else if (ty > hist_offset + (screenheight-1))
  893.     i = ty-hist_offset-(screenheight-1);
  894.   if (i > 0)
  895.     yend -= MarkScrollUpDisplay(i);
  896.   else if (i < 0)
  897.     ystart += MarkScrollDownDisplay(-i);
  898.  
  899.   if (second == 0)
  900.     {
  901.       GotoPos(tx, W2D(cy));
  902.       return;
  903.     }
  904.   
  905.   qq = x1 + y1 * screenwidth;
  906.   ff = fx + fy * screenwidth; /* "from" offset in WIN coords */
  907.   tt = tx + ty * screenwidth; /* "to" offset  in WIN coords*/
  908.  
  909.   if (ff > tt)
  910.     {
  911.       st = tt; en = ff;
  912.       x = tx; y = ty;
  913.     }
  914.   else
  915.     {
  916.       st = ff; en = tt;
  917.       x = fx; y = fy;
  918.     }
  919.   if (st > qq)
  920.     {
  921.       st++;
  922.       x++;
  923.     }
  924.   if (en < qq)
  925.     en--;
  926.   if (tt > qq)
  927.     {
  928.       revst = qq; reven = tt;
  929.     }
  930.   else
  931.     {
  932.       revst = tt; reven = qq;
  933.     }
  934.   ry = y - hist_offset;
  935.   if (ry < ystart)
  936.     {
  937.       y += (ystart - ry);
  938.       x = 0;
  939.       st = y * screenwidth;
  940.       ry = ystart;
  941.     }
  942.   for (t = st; t <= en; t++, x++)
  943.     {
  944.       if (x >= screenwidth)
  945.     {
  946.       x = 0;
  947.       y++, ry++;
  948.     }
  949.       if (ry > yend)
  950.     break;
  951.       if (t == st || x == 0)
  952.     {
  953.       for (ce = screenwidth-1; ce >= 0; ce--)
  954.         if (iWIN(y)[ce] != ' ')
  955.           break;
  956.     }
  957.       if (x <= ce && x >= left_mar && x <= right_mar
  958.           && (LP || x < screenwidth-1 || ry < screenbot))
  959.     {
  960.       GotoPos(x, W2D(y));
  961.       if (t >= revst && t <= reven)
  962.         SaveSetAttr(A_SO, ASCII);
  963.       else
  964.         SaveSetAttr(aWIN(y)[x], fWIN(y)[x]);
  965.       PUTCHAR(iWIN(y)[x]);
  966.     }
  967.     }
  968.   GotoPos(tx, W2D(cy));
  969. }
  970.  
  971. static void AbortMarkRoutine()
  972. {
  973.   int yend, redisp;
  974.  
  975.   yend = screenheight - 1;
  976.   redisp = second;
  977.   if (fore->histheight - hist_offset < screenheight)
  978.     {
  979.       second = 0;
  980.       yend -= MarkScrollUpDisplay(fore->histheight - hist_offset);
  981.     }
  982.   if (hist_offset != fore->histheight)
  983.     {
  984.       in_ovl = 0;    /* So we can use Activate() */
  985.       Activate(0);    /* to do a complete redisplay */
  986.     }
  987.   else
  988.     {
  989.       rem(x1, y1, cx, cy, redisp, (char *)0, yend);
  990.     }
  991.   ExitOverlayPage();
  992.   in_mark = 0;
  993. }
  994.  
  995.  
  996. static void MarkRedisplayLine(y, xs, xe, isblank)
  997. int y; /* NOTE: y is in DISPLAY coords system! */
  998. int xs, xe;
  999. int isblank;
  1000. {
  1001.   int x, i, rm;
  1002.   int sta, sto, cp; /* NOTE: these 3 are in WINDOW coords system */
  1003.   char *wi, *wa, *wf, *oldi;
  1004.  
  1005.   InsertMode(0); /* Not done in DisplayLine() */
  1006.  
  1007.   wi = iWIN(D2W(y));
  1008.   wa = aWIN(D2W(y));
  1009.   wf = fWIN(D2W(y));
  1010.   oldi = isblank ? blank : null;
  1011.  
  1012.   if (second == 0)
  1013.     {
  1014.       DisplayLine(oldi, null, null, wi, wa, wf, y, xs, xe);
  1015.       return;
  1016.     }
  1017.  
  1018.   sta = y1 * screenwidth + x1;
  1019.   sto = cy * screenwidth + cx;
  1020.   if (sta > sto)
  1021.     {
  1022.       i=sta; sta=sto; sto=i;
  1023.     }
  1024.   cp = D2W(y) * screenwidth + xs;
  1025.  
  1026.   rm = right_mar;
  1027.   for (x = screenwidth - 1; x >= 0; x--)
  1028.     if (wi[x] != ' ')
  1029.       break;
  1030.   if (x < rm)
  1031.     rm = x;
  1032.  
  1033.   for (x = xs; x <= xe; x++, cp++)
  1034.     if (cp >= sta && x >= left_mar)
  1035.       break;
  1036.   if (x > xs)
  1037.     DisplayLine(oldi, null, null, wi, wa, wf, y, xs, x-1);
  1038.   for (; x <= xe; x++, cp++)
  1039.     {
  1040.       if (cp > sto || x > rm || (!LP && x >= screenwidth-1 && y == screenbot))
  1041.     break;
  1042.       GotoPos(x, y);
  1043.       SaveSetAttr(A_SO, ASCII);
  1044.       PUTCHAR(wi[x]);
  1045.     }
  1046.   if (x<=xe)
  1047.     DisplayLine(oldi, null, null, wi, wa, wf, y, x, xe);
  1048. }
  1049.  
  1050.  
  1051. static int
  1052. MarkRewrite(ry, xs, xe, doit)
  1053. int ry, xs, xe, doit;
  1054. {
  1055.   int dx, x, y, st, en, t, rm;
  1056.   char *a, *f, *i;
  1057.  
  1058.   y = D2W(ry);
  1059.   dx = xe - xs;
  1060.   if (doit)
  1061.     {
  1062.       i = iWIN(y) + xs;
  1063.       while (dx--)
  1064.         PUTCHAR(*i++);
  1065.       return(0);
  1066.     }
  1067.   
  1068.   a = aWIN(y) + xs,
  1069.   f = fWIN(y) + xs;
  1070.   if (second == 0)
  1071.     st = en = -1;
  1072.   else
  1073.     {
  1074.       st = y1 * screenwidth + x1;
  1075.       en = cy * screenwidth + cx;
  1076.       if (st > en)
  1077.         {
  1078.           t = st; st = en; en = t;
  1079.         }
  1080.     }
  1081.   t = y * screenwidth + xs;
  1082.   for (rm=screenwidth-1, i=iWIN(y) + screenwidth-1; rm>=0; rm--)
  1083.     if (*i-- != ' ')
  1084.       break;
  1085.   if (rm > right_mar)
  1086.     rm = right_mar;
  1087.   x = xs;
  1088.   while (dx--)
  1089.     {
  1090.       if (t >= st && t <= en && x >= left_mar && x <= rm)
  1091.         {
  1092.       if (GlobalAttr != A_SO || GlobalCharset != ASCII)
  1093.         return(EXPENSIVE);
  1094.         }
  1095.       else
  1096.         {
  1097.       if (GlobalAttr != *a || GlobalCharset != *f)
  1098.         return(EXPENSIVE);
  1099.         }
  1100.       a++, f++, t++, x++;
  1101.     }
  1102.   return(xe - xs);
  1103. }
  1104.  
  1105.  
  1106. /*
  1107.  * scroll the screen contents up/down.
  1108.  */
  1109. static int MarkScrollUpDisplay(n)
  1110. int n;
  1111. {
  1112.   int i;
  1113.  
  1114.   debug1("MarkScrollUpDisplay(%d)\n", n);
  1115.   if (n <= 0)
  1116.     return 0;
  1117.   if (n > fore->histheight - hist_offset)
  1118.     n = fore->histheight - hist_offset;
  1119.   i = (n < screenheight) ? n : (screenheight);
  1120.   ScrollRegion(0, screenheight - 1, i);
  1121.   hist_offset += n;
  1122.   while (i-- > 0)
  1123.     MarkRedisplayLine(screenheight-i-1, 0, screenwidth-1, 1);
  1124.   return n;
  1125. }
  1126.  
  1127. static int MarkScrollDownDisplay(n)
  1128. int n;
  1129. {
  1130.   int i;
  1131.  
  1132.   debug1("MarkScrollDownDisplay(%d)\n", n);
  1133.   if (n <= 0)
  1134.     return 0;
  1135.   if (n > hist_offset)
  1136.     n = hist_offset;
  1137.   i = (n < screenheight) ? n : (screenheight);
  1138.   ScrollRegion(0, screenheight - 1, -i);
  1139.   hist_offset -= n;
  1140.   while (i-- > 0)
  1141.     MarkRedisplayLine(i, 0, screenwidth-1, 1);
  1142.   return n;
  1143. }
  1144.  
  1145.